﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Collections;
using System.IO;
using System.Windows.Media;

namespace Faust.Andrew.MTG
{
    [Serializable]
    [DataContract]
    public class Card : IEquatable<Card>, IEquatable<string>, IEquatable<DeckCard>,INotifyPropertyChanged, ICloneable
    {
        private string _multiverseID;
        
        [DataMember]
        public string MultiverseID
        {
            get
            {
                return _multiverseID;
            }
            set
            {
                if (_multiverseID != value)
                {
                    _multiverseID = value;
                    FirePropertyChangedEvent("MultiverseID");
                }                
            }
        }
        
        private string _rarity;
        public string Rarity
        {
            get
            {
                return _rarity;
            }
            set
            {
                if (_rarity != value)
                {
                    _rarity = value;
                    FirePropertyChangedEvent("Rarity");
                }
            }
        }
        
        private string _toughness;
        public string Toughness
        {
            get
            {
                return _toughness;
            }
            set
            {
                if (_toughness != value)
                {
                    _toughness = value;
                    Int32.TryParse(_toughness, out _toughnessNumeric);
                    FirePropertyChangedEvent("Toughness");
                }
            }
        }

        private int _toughnessNumeric;
        public int ToughnessNumeric
        {
            get { return _toughnessNumeric; }
            set
            {
                if (_toughnessNumeric != value)
                {
                    _toughnessNumeric = value;
                    FirePropertyChangedEvent("ToughnessNumeric");
                }
            }
        }        
        
        private string _power;
        public string Power
        {
            get
            {
                return _power;
            }
            set
            {
                if (_power != value)
                {
                    _power = value;
                    Int32.TryParse(_power, out _powerNumeric);
                    FirePropertyChangedEvent("Power");
                }
            }
        }

        private int _powerNumeric;
        public int PowerNumeric
        {
            get { return _powerNumeric; }
            set
            {
                if (_powerNumeric != value)
                {
                    _powerNumeric = value;
                    FirePropertyChangedEvent("PowerNumeric");
                }
            }
        }        
        
        private string _cardTypes;
        public string CardTypes
        {
            get
            {
                return _cardTypes;
            }
            set
            {
                if (_cardTypes != value)
                {
                    _cardTypes = value;
                    FirePropertyChangedEvent("CardTypes");
                }
            }
        }

        private string _subType;
        public string SubType
        {
            get { return _subType; }
            set
            {
                if (_subType != value)
                {
                    _subType = value;
                    FirePropertyChangedEvent("SubType");
                }
            }
        }

        private string _expansion;
        public string Expansion
        {
            get { return _expansion; }
            set
            {
                if (_expansion != value)
                {
                    _expansion = value;
                    FirePropertyChangedEvent("Expansion");
                }
            }
        }
        
        
        private string _convertedManaCost;
        public string ConvertedManaCost
        {
            get
            {
                return _convertedManaCost;
            }
            set
            {
                if (_convertedManaCost != value)
                {
                    _convertedManaCost = value;
                    Int32.TryParse(_convertedManaCost, out _convertedManaCostNumeric);
                    FirePropertyChangedEvent("ConvertedManaCost");
                }
            }
        }

        private int _convertedManaCostNumeric;
        public int ConvertedManaCostNumeric
        {
            get { return _convertedManaCostNumeric; }
            set
            {
                if (_convertedManaCostNumeric != value)
                {
                    _convertedManaCostNumeric = value;
                    FirePropertyChangedEvent("ConvertedManaCostNumeric");
                }
            }
        }

        protected MemoryStream _imageStream;
        protected ImageSource _imageSource;

        public Image CardImage
        {
            get
            {
                if (_imageStream == null)
                {
                    return null;
                }
                else
                {
                    return LoadImage();
                }
            }
        }

        public System.Windows.Media.ImageSource ImageSource
        {
            get
            {
                //If the imagesource was set directly then return it, otherwise load it from the stream.
                if (_imageSource != null) { return _imageSource; }

                if (_imageStream == null)
                {
                    return null;
                }
                else
                {
                    return LoadImageSource();
                }
            }
        }

        protected System.Drawing.Image LoadImage()
        {
            _imageStream.Seek(0, System.IO.SeekOrigin.Begin);
            return System.Drawing.Image.FromStream(_imageStream);
        }

        protected System.Windows.Media.ImageSource LoadImageSource()
        {
            _imageStream.Seek(0, System.IO.SeekOrigin.Begin);
            System.Windows.Media.Imaging.BitmapImage image = new System.Windows.Media.Imaging.BitmapImage();
            image.BeginInit();
            image.StreamSource = _imageStream;
            image.EndInit();

            return image;
        }

        public void SetImage(string path)
        {
            using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                SetImage(fileStream);
            }
        }

        public Stream GetImageStream()
        {
            return _imageStream;
        }

        public void SetImage(ImageSource imageSource)
        {
            _imageSource = imageSource;
        }

        public void SetImage(Stream stream)
        {
            if (stream.CanSeek)
            {
                stream.Seek(0, SeekOrigin.Begin);
            }

            MemoryStream memoryStream = new MemoryStream();

            int bufferSize = 4096;
            byte[] data = new byte[bufferSize];
            int bytesRead = 0;

            while ((bytesRead = stream.Read(data, 0, bufferSize)) > 0)
            {
                memoryStream.Write(data, 0, bytesRead);
            }

            _imageStream = memoryStream;

            FirePropertyChangedEvent("CardImage");
            FirePropertyChangedEvent("ImageSource");
        }

        private string _name;
        [DataMember]
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                if (_name != value)
                {
                    _name = value;
                    FirePropertyChangedEvent("Name");
                }
            }
        }

        private string _cardText;
        public string CardText
        {
            get
            {
                return _cardText;
            }
            set
            {
                if (_cardText != value)
                {
                    _cardText = value;
                    FirePropertyChangedEvent("CardText");
                }
            }
        }
        
        private string _manaCost;
        public string ManaCost
        {
            get
            {
                return _manaCost;
            }
            set
            {
                if (_manaCost != value)
                {
                    _manaCost = value;
                    SetColor();
                    FirePropertyChangedEvent("ManaCost");
                }
            }
        }

        private string _color;
        public string Color
        {
            get
            {
                if (String.IsNullOrEmpty(_color) && !String.IsNullOrEmpty(_manaCost))
                {
                    SetColor();
                }

                return _color;
            }
        }

        private int _quantity;
        public int Quantity
        {
            get { return _quantity; }
            set
            {
                if (value < 0)
                {
                    value = 0;
                }

                if (_quantity != value)
                {
                    _quantity = value;
                    FirePropertyChangedEvent("Quantity");
                }
            }
        }

        private int _inUse;
        public int InUse
        {
            get
            {
                return _inUse;
            }
            set
            {
                if (_inUse != value)
                {
                    _inUse = value;
                    FirePropertyChangedEvent("InUse");
                }
            }
        }

        private bool _detailsLoaded;
        public bool DetailsLoaded
        {
            get
            {
                return _detailsLoaded;
            }
            set
            {
                if (_detailsLoaded != value)
                {
                    _detailsLoaded = value;
                    FirePropertyChangedEvent("DetailsLoaded");
                }
            }
        }

        private void CheckSetColor(string colorToCheck, ref string currentColor, ref bool isColorSet)
        {
            string tempCost = _manaCost.ToUpper();

            if (tempCost.IndexOf(colorToCheck.ToUpper()) >= 0)
            {
                if (isColorSet)
                {
                    currentColor = "Multi";
                }
                else
                {
                    currentColor = colorToCheck;
                }

                isColorSet = true;
            }
        }

        private void SetColor()
        {
            if (!String.IsNullOrEmpty(_color)) { return; }

            if (String.IsNullOrEmpty(_manaCost))
            {
                _color = "Colorless";
                return;
            }

            bool isSet = false;
            string currentColor = "Colorless";

            CheckSetColor("Red", ref currentColor, ref isSet);
            CheckSetColor("Green", ref currentColor, ref isSet);
            CheckSetColor("Blue", ref currentColor, ref isSet);
            CheckSetColor("Black", ref currentColor, ref isSet);
            CheckSetColor("White", ref currentColor, ref isSet);

            _color = currentColor;

            FirePropertyChangedEvent("Color");
        }

        public void CopyFrom(Card card)
        {
            Rarity = card.Rarity;
            Toughness = card.Toughness;
            ToughnessNumeric = card.ToughnessNumeric;
            Power = card.Power;
            PowerNumeric = card.PowerNumeric;
            CardTypes = card.CardTypes;
            ConvertedManaCost = card.ConvertedManaCost;
            ConvertedManaCostNumeric = card.ConvertedManaCostNumeric;            
            SetImage(card._imageStream);
            Name = card.Name;
            CardText = card.CardText;
            ManaCost = card.ManaCost;
            Quantity = card.Quantity;
            InUse = card.InUse;
        }

        #region IEquatable<Card> Members

        public bool Equals(Card other)
        {
            return String.Equals(MultiverseID, other.MultiverseID, StringComparison.InvariantCultureIgnoreCase);
        }
        #endregion

        #region IEquatable<string> Members

        public bool Equals(string other)
        {
            return String.Equals(MultiverseID, other, StringComparison.InvariantCultureIgnoreCase);
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void FirePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));                                
            }
        }

        #endregion

        public object Clone()
        {
            Card card = new Card();
            card.CopyFrom(this);
            return card;
        }

        #region IEquatable<DeckCard> Members

        public bool Equals(DeckCard other)
        {
            return String.Equals(MultiverseID, other.Card.MultiverseID, StringComparison.InvariantCultureIgnoreCase);
        }

        #endregion
    }
}